import isPlainObject from 'lodash/isPlainObject'
import $$observable from 'symbol-observable'

/**
 * These are private action types reserved by Redux.
 * For any unknown actions, you must return the current state.
 * If the current state is undefined, you must return the initial state.
 * Do not reference these action types directly in your code.
 * 
 * 这些都是redux本身预置的私有action types 
 * 对于任何未知的action, 你一定要return当前的state.
 * 如果当前的state是undefined, 你一定要return最初始的state.
 * 一定,一定,一定不要在代码中直接引用action types .
 */
export const ActionTypes = {  //初始化action的type,没有action参数的时候用
  INIT: '@@redux/INIT'
}

/**
 * Creates a Redux store that holds the state tree.
 * The only way to change the data in the store is to call `dispatch()` on it.
 * There should only be a single store in your app. To specify how different
 * parts of the state tree respond to actions, you may combine several reducers
 * into a single reducer function by using `combineReducers`.
 *
 * 创建一个包含state tree(状态树)的redux store.
 * 唯一改变store中data(数据)的方法是调用`dispatch()`方法.
 * 在你的程序中应该只存在唯一一个store, 来表明state tree各部分怎样对action做出反应
 * 你可能需要将多个reducer用`combineReducers`组合在一起
 * 
 * @param {Function} reducer A function that returns the next state tree, given
 * the current state tree and the action to handle.
 * 
 * @param {Function} reducer 参数reducer是一个返回下一个state tree(状态树)的函数,来操作当前的state和action
 *
 * @param {any} [preloadedState] The initial state. You may optionally specify it
 * to hydrate the state from the server in universal apps, or to restore a
 * previously serialized user session.
 * If you use `combineReducers` to produce the root reducer function, this must be
 * an object with the same shape as `combineReducers` keys.
 * 
 * @param {any} [preloadedState] 初始化的state,可选参数,你可以在universal(一般的,普遍的,我不知道怎么说比较合适)
 * 的程序中与服务器的state结合,或者restore一个预先连续的user session(直译过来的,一般用不到)
 * 如果你用`combineReducers`产生一个根reducer函数,这一定是一个和`combineReducers`的key一样的对象(根reducer是一个对象)
 *
 * @param {Function} [enhancer] The store enhancer. You may optionally specify it
 * to enhance the store with third-party capabilities such as middleware,
 * time travel, persistence, etc. The only store enhancer that ships with Redux
 * is `applyMiddleware()`.
 * 
 * @param {Function} [enhancer] store增强器. 可选参数.用来增强第三方库的能力集(这个词是直译),
 * 比如中间件,时空穿越,和持续性(也是直译).redux的store增强器是`applyMiddleware()`
 *
 * @returns {Store} A Redux store that lets you read the state, dispatch actions
 * and subscribe to changes.
 * 
 * @returns {Store} 返回值 一个redux的store,让你可以读取state, dispatch actions 和订阅更改
 */

//createStore的目的只是创建一个store,这个store包含5个方法(一般只用到3个,最常用的是dispatch)
export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')//期望enhancer是个函数
    }
    // 当enhancer是函数的时候返回,然后执行,并将createStore作为参数传入,然后createStore就在enhancer里面
    //去执行了
    return enhancer(createStore)(reducer, preloadedState)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  let currentReducer = reducer  //一般此reducer不是单个的reducer函数,而是combineReducers函数
  let currentState = preloadedState
  let currentListeners = []  //监听函数
  let nextListeners = currentListeners
  let isDispatching = false

  function ensureCanMutateNextListeners() { //nextListeners不是currentListeners
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }

  /**
   * Reads the state tree managed by the store.
   *
   * 读取被store管理的state树
   * 
   * @returns {any} The current state tree of your application.
   * 
   *返回你的程序的当前的state树 
   */
  function getState() {
    return currentState
  }

  /**
   * Adds a change listener. It will be called any time an action is dispatched,
   * and some part of the state tree may potentially have changed. You may then
   * call `getState()` to read the current state tree inside the callback.
   *
   * 添加一个改变事件,任何时候一个action被dispatch这个事件就会被调用,然后state树的某一部分就
   * 会改变. 你也可以在回调函数里面调用`getState()`来查看当前的state树
   * 
   * You may call `dispatch()` from a change listener, with the following
   * caveats:
   *
   * 以下几种情况你也可以调用`dispatch()`
   * 
   * 1. The subscriptions are snapshotted just before every `dispatch()` call.
   * If you subscribe or unsubscribe while the listeners are being invoked, this
   * will not have any effect on the `dispatch()` that is currently in progress.
   * However, the next `dispatch()` call, whether nested or not, will use a more
   * recent snapshot of the subscription list.
   *
   * 每次调用`dispatch`之前,订阅都会被snapshot,
   * 当事件被触发的时候你订阅或者不订阅,在当前的进程中都不会对`dispatch`有什么影响
   * 然而当下一次`dispatch`被调用时,无论嵌套与否,将会使用最近的订阅列表的snapshot
   * 
   * 2. The listener should not expect to see all state changes, as the state
   * might have been updated multiple times during a nested `dispatch()` before
   * the listener is called. It is, however, guaranteed that all subscribers
   * registered before the `dispatch()` started will be called with the latest
   * state by the time it exits.
   *
   * 不要期待监听事件可以看到所有的状态改变,因为在事件被调用前,state在嵌套的`dispatch`间
   * 可能已经更新了很多次
   * 
   * @param {Function} listener A callback to be invoked on every dispatch.
   * 每次dispatch都会被出发的回调函数
   * 
   * @returns {Function} A function to remove this change listener.
   * 返回一个移除该事件的函数
   */
  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener) //添加事件到nextListeners数组

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1) //从nextListeners数组中移除事件
    }
  }

  /**
   * Dispatches an action. It is the only way to trigger a state change.
   *
   * dispatch  action是唯一触发state改变的途径
   * 
   * The `reducer` function, used to create the store, will be called with the
   * current state tree and the given `action`. Its return value will
   * be considered the **next** state of the tree, and the change listeners
   * will be notified.
   *
   * `reducer`函数,被用来创建store,有当前的state树和action就会被调用(state和action是reducer函数的参数)
   * 它的返回值会被当做下一个state树.监听事件会注意到state树的改变
   * 
   * The base implementation only supports plain object actions. If you want to
   * dispatch a Promise, an Observable, a thunk, or something else, you need to
   * wrap your store creating function into the corresponding middleware. For
   * example, see the documentation for the `redux-thunk` package. Even the
   * middleware will eventually dispatch plain object actions using this method.
   *
   * 最基本的用法是仅支持 为纯对象的 action,如果你想要dispatch一个promise,一个Observable,
   * thunk,或是其他东西,你需要封装store创建一个进入到相应中间件的函数.  比如,看一个`redux-thunk`
   * 的文档,即使是中间件最终也会用这个方法dispatch  纯对象的action
   * 
   * @param {Object} action A plain object representing “what changed”. It is
   * a good idea to keep actions serializable so you can record and replay user
   * sessions, or use the time travelling `redux-devtools`. An action must have
   * a `type` property which may not be `undefined`. It is a good idea to use
   * string constants for action types.
   *
   * action是一个纯对象,代表'什么被改变了'. 保持action的连续性是个好主意,这样你就可以记录和
   * 重现user session,或者使用时空穿梭`redux-devtools`. 
   * action必须包含一个`type`属性,即使是`undefined`. 通常使用字符串常量表示
   * 
   * @returns {Object} For convenience, the same action object you dispatched.
   *
   * 为了方便,返回你dispatch的action
   * 
   * Note that, if you use a custom middleware, it may wrap `dispatch()` to
   * return something else (for example, a Promise you can await).
   * 注意 如果你想使用特定的中间件,可封装`dispatch`返回其他东西(比如, 一个异步调用的promise)
   * 
   */
  function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )//actions必须为纯对象,使用特定中间件异步调用actions
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )//actions可能有一个未定义的type属性,你可能拼错了这个常量
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')//reducer没有dispatch action
    }

    try {
      isDispatching = true
      //dispatch的目的就是改变currentState
      currentState = currentReducer(currentState, action) //currentReducer = reducer
    } finally {
      isDispatching = false
    }

    const listeners = currentListeners = nextListeners  //订阅函数的事件
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

  /**
   * Replaces the reducer currently used by the store to calculate the state.
   *
   * 替换 store 当前用来计算 state 的 reducer。
   * 
   * You might need this if your app implements code splitting and you want to
   * load some of the reducers dynamically. You might also need this if you
   * implement a hot reloading mechanism for Redux.
   *
   * 这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。
   *在实现 Redux 热加载机制的时候也可能会用到
   * 
   * @param {Function} nextReducer The reducer for the store to use instead.
   * store所替换的reducer
   * @returns {void}
   */
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer
    dispatch({ type: ActionTypes.INIT })
  }

  /**
   * Interoperability point for observable/reactive libraries.
   * @returns {observable} A minimal observable of state changes.
   * For more information, see the observable proposal:
   * https://github.com/tc39/proposal-observable
   * 
   * observable/reactive库的互用性
   * observable是一个mini的 可观察state的改变
   * 在下面这个网址查看更多observable的信息
   */
  function observable() {
    const outerSubscribe = subscribe
    return {
      /**
       * The minimal observable subscription method.
       * @param {Object} observer Any object that can be used as an observer.
       * The observer object should have a `next` method.
       * @returns {subscription} An object with an `unsubscribe` method that can
       * be used to unsubscribe the observable from the store, and prevent further
       * emission of values from the observable.
       * 
       * mini的可观察订阅的方法
       * observer是 任何对象都可以用作观察者,这个观察者应该有一个`next`方法
       * subscription 一个有`unsubscribe`方法的对象.可以用做退订observable,防止进一步发出value值
       * (我也不知道什么意思,外国人说话比较随意)
       */
      subscribe(observer) {
        if (typeof observer !== 'object') {
          throw new TypeError('Expected the observer to be an object.')
        }

        function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }

        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },

      [$$observable]() {
        return this
      }
    }
  }

  // When a store is created, an "INIT" action is dispatched so that every
  // reducer returns their initial state. This effectively populates
  // the initial state tree.
  /** 
   * 当创建一个store的时候,一个初始的action就被dispatch了,所以每个reducer都会返回初始的state
   * 这个可以很高效的得到state树
  */
  dispatch({ type: ActionTypes.INIT })

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
}

源码解析请参考 https://segmentfault.com/a/11...


杨柳岸残月孤轮
44 声望1 粉丝